//General
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;

//Project
using CS6238Project2;
using CS6238Project2.Banking.Commerce;
using CS6238Project2.Banking.Communication;
using CS6238Project2.Banking.Tools;
using CS6238Project2.Banking.Entity;

//Serialization
using System.IO;
using System.Xml;
using System.Xml.Serialization;

using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters;
using System.Runtime.Serialization.Formatters.Binary;


namespace CS6238Project2.GUI
{
    [Serializable]
    public partial class BankDisplay : Form
    {
        /*
         * TODO:
         *  Network:
         *  Handling of receiver
         *  Handling of Transmitter
         *  Handling of Network Config changing receiver/transmitter
         *          -Use the networkWindow_ButtonClicked method.
         *          -e contains all necessary data.
         *  Handling of sending parcels for ProcessParcel
         * 
         * 
         * 
         * 
         * 
         * OPTIONAL:
         *  Various Sorting
         */


        private Bank bank;//the bank object
        private NetworkControlForm networkWindow;//network controls
        private Server server;
        private int selectedRow;
        private Parcel globalParcel;




        public Bank Bank
        {
            get { return bank; }
            set { bank = value; }
        }


        public BankDisplay()
        {
            bank = new Bank();
            bank.Account = new Account();
            InitializeComponent();
            server = new Server(8000,true);
            server.ParcelPassed += new Server.ParcelDelegate(Parcel_Received);
            

            networkWindow = new NetworkControlForm();//set up network control
            bank.Name = "Bank of America";//my bank :D

            bank.Accounts = new BindingList<Account>();
            bank.Accounts.Add(new Account());
            //Must initialize with atleast one datapoint?
            bankBindingSource.DataSource = bank;
            //recordBindingSource.DataSource = bank.Accounts[0].Record;
            //accountsBindingSource.DataSource = bank.Accounts;
            
            testrun(); //creates a simple test run
        }
       
        

        /// <summary>
        /// This will be deleted eventually, is just here to test stuff.
        /// </summary>
        private void testrun()
        {
            Parcel registration = new Parcel();
            registration = new Parcel("Dan", "Bank of America", "Registration Request");
            bank.ProcessParcel(registration);

            bank.Accounts[1].Record.Add(new Transaction("B", "B", 1, 1, DateTime.Now));
            bank.Accounts[1].Record.Add(new Transaction("B", "B", 1, 1, DateTime.Now));
            bank.Accounts[1].Record.Add(new Transaction("B", "B", 1, 1, DateTime.Now));

            
            registration = new Parcel("Bill", "Bank of America", "Registration Request");
            bank.ProcessParcel(registration);

            registration = new Parcel("Bob", "Bank of America", "Registration Request");
            bank.ProcessParcel(registration);

            registration = new Parcel("Darryl", "Bank of America", "Registration Request");
            bank.ProcessParcel(registration);

            this.Text = bank.Name;
        }





        /************************************************************************************/
        /***                        GLOBAL EVENT HANDLING                                 ***/
        /************************************************************************************/


        // used to make thread safe calls
        private Thread dataThread;
        private void Parcel_Received(Parcel parcel)
        {
            Console.WriteLine(
                "Sender: " + parcel.Sender +
                "\nReceiver: " + parcel.Receiver +
                "\nType: " + parcel.Type +
                "\nMessageData: " + parcel.MessageData + "\n"
            );
            globalParcel = parcel;
            dataThread = new Thread(new ThreadStart(this.ThreadProcSafe));
            this.dataThread.Start();
        }

        // This method is executed on the worker thread and makes
        // a thread-safe call on the MainApp control.
        private void ThreadProcSafe()
        {
            if (accountControlsTable.InvokeRequired)
            {
                accountControlsTable.Invoke(new MethodInvoker(ProcessParcel));
            }
            else
            {
                ProcessParcel();
            }
        }










        /************************************************************************************/
        /***                          HANDLE ACCOUNT TABLE                                ***/
        /************************************************************************************/

        /// <summary>
        /// This activates when a row is activated.  It spools the contents of
        /// the selected account into the transaction record.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void AccountTable_RowEnter(object sender, DataGridViewCellEventArgs e)
        {
            int index = bank.Accounts.IndexOf((Account)accountsBindingSource[e.RowIndex]);
            try
            {
                
                selectedRow = e.RowIndex;
                recordBindingSource.DataSource = bank.Accounts[selectedRow].Record;
                bank.Account.Record = bank.Accounts[index].Record;
                
            }
            catch (Exception exception)
            {
                MessageBox.Show(exception.Message);
            }

        }
        

        /// <summary>
        /// This method automatically formats the coloring of the Account table
        /// to display green when positive, black neutral, red when negative.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void AccountTable_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
        {
            /*
             * TODO:
             *  NOTHING
             */
            
            try
            {
                
                //This selects the balance column
                if (e.ColumnIndex == 2)
                {
                    
                    Account acct = (Account)accountsBindingSource[e.RowIndex];
                    if (acct.Balance < 0)//If the balance is negative
                    {
                        //color red
                        accountControlsTable[e.ColumnIndex, e.RowIndex].
                            Style.ForeColor = Color.Red;
                    }
                    else if (acct.Balance > 0)//if the balance is positive
                    {
                        //color green
                        accountControlsTable[e.ColumnIndex, e.RowIndex].
                            Style.ForeColor = Color.Green;
                    }
                    else//if the balance is neutral
                    {
                        //color black
                        accountControlsTable[e.ColumnIndex, e.RowIndex].
                            Style.ForeColor = Color.Black;
                    }
                }
            }
            catch (ArgumentOutOfRangeException exception)
            {
                MessageBox.Show(exception.Message);
            }
        }




        /// <summary>
        /// This button handles the DELETION of an account.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void accountControlsCloseButton_Click(object sender, EventArgs e)
        {
            /*
             * TODO:
             *  NOTHING
             */
            Account account = new Account();
            string name = "";
            Certificate cert = new Certificate();
            //Grab the account and it's name, as well as its certificate
            try
            {
                account = (Account)accountControlsTable.
                                Rows[selectedRow].DataBoundItem;
                name = account.Name;
                cert = bank.RetrieveCertificate(name, false);
            }
            catch (Exception exception)
            {
                Console.WriteLine(exception);
            }
            //Confirm you want to delete
            DialogResult result = MessageBox.Show("Are you sure you want to close "  
                + name +"'s account?  "
                + "It is permanent", "Account Closing", MessageBoxButtons.YesNo);

            
            if (DialogResult.Yes == result)
            {
                try
                {
                    //Remove them from the binding source
                    accountsBindingSource.Remove((object)account);
                    //Now remove them in general
                    bank.Accounts.Remove(account);
                    //finally, remove the certificate
                    bank.Certificates.Remove(cert);
                }
                catch(Exception exception)
                {
                    MessageBox.Show(exception.Message);
                }
            }
            

        }

        /************************************************************************************/
        /***                       HANDLE TRANSACTION TABLE                               ***/
        /************************************************************************************/




        /// <summary>
        /// This method autometically formats the coloring of the Transaction Record
        /// to display green when positive, black neutral, red when negative.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void RecordTable_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
        {

            /*
             * TODO:
             *  NOTHING
             */
            try
            {
                if (e.ColumnIndex == 3)
                {
                    Transaction trans = (Transaction)recordBindingSource[e.RowIndex];
                    if (trans.Adjustment < 0)
                    {

                        transactionRecordTable[e.ColumnIndex, e.RowIndex].Style.ForeColor = Color.Red;
                    }
                    else if (trans.Adjustment > 0)
                    {

                        transactionRecordTable[e.ColumnIndex, e.RowIndex].Style.ForeColor = Color.Green;
                    }
                    else
                    {

                        transactionRecordTable[e.ColumnIndex, e.RowIndex].Style.ForeColor = Color.Black;
                    }
                }
            }
            catch (ArgumentOutOfRangeException exception)
            {
                MessageBox.Show(exception.Message);
            }
        }

      

        /************************************************************************************/
        /***                                NETWORK CONTROLS                              ***/
        /************************************************************************************/


        private void connectionToolStripMenuItem_Click(object sender, EventArgs e)
        {
            /*
             * TODO:
             *  When first created, get port data from the transmitter/receiver
             *  When first created, determine connection status (virtual)
             * 
             */
            networkWindow = new NetworkControlForm();
            //networkWindow.listeningPort = 
            //networkWindow.sendingPort =
            networkWindow.Show();

        }



        private void testBox()
        {
           
            networkWindow.NetworkEvent +=
                new NetworkControlForm.
                NetworkControlHandler(networkWindow_ButtonClicked);
            networkWindow.Show();

        }

        private void networkWindow_ButtonClicked(object sender, NetworkControlEventArgs e)
        {
            try
            {
                bool DeterminesWhatConnectionButtonSays = e.Connected;
                int thisIsTheListeningPortValue = e.ListeningPort;
                int thisIsTheSendingPortValue = e.SendingPort;
                //Update network settings
            }
            catch (Exception exception)
            {
                MessageBox.Show(exception.Message);
            }
            //INCOMPLETE
        }


        /************************************************************************************/
        /***                             PASSIVE FUNCTIONS                                ***/
        /************************************************************************************/


        //I am unsure how these should work, but something like this:

        /// <summary>
        /// Processes incoming information, after the receiver turns the incoming data
        /// into parcels to present to this function
        /// </summary>
        /// <param name="parcel">The incoming parcel</param>
        private void ProcessParcel()
        {
            //First put it into here...
            
            try
            {
                //this parcel is for us
                if ((globalParcel.Receiver == "Bank of America") || (globalParcel.Type == "Dual Transaction"))
                {
                    string ip = globalParcel.SenderAddr;
                    globalParcel = bank.ProcessParcel(globalParcel);

                    //There are no known special actions I am aware of at the moment....
                    if (globalParcel.Type == "Dual Transaction Response")
                    {
                        RouteParcel();
                    }
                    else if (globalParcel.Type != "Terminate")
                    {
                        //send to the ip, port, parcel
                        server.Send(ip, globalParcel.SenderPort, globalParcel);
                    }
                    
                }
                //its for someone else, forward it to the appropriate entity
                else
                {
                    RouteParcel();
                }
            }
            catch (Exception exception)
            {
                MessageBox.Show(exception.Message);
            }
            //INCOMPLETE


        }


        /// <summary>
        /// Routes network traffic not directed at the bank.
        /// </summary>
        private void RouteParcel()
        {
            int port = -1;
            string ip = null;
            if (bank.Merchants != null)
            {
                foreach (AddressEntry entry in bank.Merchants)
                {
                    if (entry.Name == globalParcel.Receiver)
                    {
                        ip = entry.IP;
                        port = entry.Port;
                    }
                }
            }

            if ((ip == null) && (bank.Users != null))
            {
                foreach (AddressEntry entry in bank.Users)
                {
                    if (entry.Name == globalParcel.Receiver)
                    {
                        ip = entry.IP;
                        port = entry.Port;
                    }
                }
            }

            if ((ip != null) && (port != -1))
            {
                server.Send(ip, port, globalParcel);
            }
        }


        private int Port()
        {
            return globalParcel.SenderPort;
        }

        private string IP()
        {
            return "192.168.0.5";
        }

        /// <summary>
        /// Gets the IP and port of the target
        /// </summary>
        /// <returns></returns>
       


        private void recordBindingSource_DataError(object sender, BindingManagerDataErrorEventArgs e)
        {
            MessageBox.Show("hi");
        }


        /// <summary>
        /// Uses serialization to save the entire kernel as a file of itself.
        /// </summary>
        /// <param name="fileName">The name for the file to be saved as.</param>
        private void save()
        {

            Stream stream = null;
            try
            {
                IFormatter formatter = new BinaryFormatter();
                stream = new FileStream(bank.Name + ".BankFile", FileMode.Create, FileAccess.Write, FileShare.None);
            
                String xmlString = Encryption.XmlString(bank);
                formatter.Serialize(stream, xmlString);
                
            }
            catch (Exception exception)
            {
                MessageBox.Show(exception.Message);
            }
            finally
            {
                if (null != stream)
                    stream.Close();
            }
            try
            {
                IFormatter formatter = new BinaryFormatter();
                stream = new FileStream(bank.Name + ".BankFile", FileMode.Create, FileAccess.Write, FileShare.None);

                String xmlString = Encryption.XmlString(bank);
                formatter.Serialize(stream, xmlString);

            }
            catch (Exception exception)
            {
                MessageBox.Show(exception.Message);
            }
            finally
            {
                if (null != stream)
                    stream.Close();
            }

        }

        private void BankDisplay_FormClosing(object sender, FormClosingEventArgs e)
        {
            save();
        }


        private void addAccount(Account account)
        {

        }


    }
}